package cn.caplike.demo.nio._2017;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * 简介：Selector Client
 *
 * @author 李珂 2017年11月23日 上午11:27:37
 */
public class SelectorTestClient {
    private Selector selector = null; // 定义检测SocketChannel的Selector对象
    private SocketChannel sc = null; // 客户端SocketChannel

    public static void main(String[] args) {
        try {
            new SelectorTestClient().init();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void init() throws IOException {
        selector = Selector.open();
        InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);
        /* 调用open静态方法创建连接到指定主机的SocketChannel */
        sc = SocketChannel.open(isa);
        sc.configureBlocking(false);
        /* 将SocketChannel对象注册到指定Selector */
        sc.register(selector, SelectionKey.OP_READ);

        /* 启动读取服务器数据的线程 */
        new Thread(new ClientThread()).start();

        /* 创建键盘输入流 */
        Scanner scan = new Scanner(System.in);
        while (scan.hasNext()) {
            String line = scan.nextLine();
            sc.write(StandardCharsets.UTF_8.encode(line));
        }
        scan.close();
    }

    /**
     * 简介：读取服务器数据的线程
     *
     * @author 李珂 2017年11月23日 下午5:21:03
     */
    private class ClientThread implements Runnable {
        /*
         * (non-Javadoc)
         *
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try {
                while (selector.select() > 0) {

                    /* 遍历每个有可用IO操作Channel对应的SelectionKey */
                    Set<SelectionKey> set = selector.selectedKeys();
                    Iterator<SelectionKey> it = set.iterator();

                    while (it.hasNext()) {
                        SelectionKey sk = it.next();
                        it.remove(); // 删除正在处理的SelectionKey

                        /* 如果当前SelectionKey对应的Channel中有可读数据 */
                        if (sk.isReadable()) {
                            SocketChannel channel = (SocketChannel) sk.channel();
                            ByteBuffer buf = ByteBuffer.allocate(1024);
                            String content = "";
                            while (channel.read(buf) > 0) {
                                buf.flip();
                                content += StandardCharsets.UTF_8.decode(buf);
                            }
                            System.out.println("Msg returned by server: " + content);
                        }
                    }

                }

            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}
